using System;
using System.Collections.Generic;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
using System.Diagnostics;
using System.Reflection;
using System.Windows.Forms;
using System.Linq;

namespace Join
{
    public class Group : IComparable<Group>
    {
        private Group()
        {
        }



        SortedDictionary<string, int> HeaderTable;

        public int CompareTo(Array array)
        {
            foreach (string header in CheckedItemCollection)
            {
                int headerIndex = HeaderTable[header];

                Debug.Assert(ArrayList.Count > 0); // real assert
                object value0 = this.ArrayList[0].GetValue(1, headerIndex);
                object value1 = array.GetValue(1, headerIndex);

                int iCompare = ExcelCompare(value0, value1);
                if (iCompare != 0)
                {
                    return iCompare;
                }
            }
            return 0;
        }


        #region IComparable<Group> Members

        public int CompareTo(Group other)
        {

            Debug.Assert(this.CheckedItemCollection.SequenceEqual(other.CheckedItemCollection)); // real assert
            foreach (string header in CheckedItemCollection)
            {
                int headerIndex0 = this.HeaderTable[header];
                int headerIndex1 = other.HeaderTable[header];

                Debug.Assert(ArrayList.Count > 0); // real assert
                object value0 = this.ArrayList[0].GetValue(1, headerIndex0);
                object value1 = other.ArrayList[0].GetValue(1, headerIndex1);

                int iCompare = ExcelCompare(value0, value1);
                if (iCompare != 0)
                {
                    return iCompare;
                }
            }
            return 0;
        }



        //See http://msdn2.microsoft.com/en-us/library/bb226682.aspx - for a list of Excel types
        //See http://www.mvps.org/dmcritchie/excel/sorting.htm#order - for how Excel sorts
        private int ExcelCompare(object value0, object value1)
        {
            //Debug.WriteLine(string.Format("comparing '{0}' to '{1}'", value0, value1));
            ExcelTypeNumber excelTypeNumber0 = GetExcelTypeNumber(value0);
            ExcelTypeNumber excelTypeNumber1 = GetExcelTypeNumber(value1);

            if (excelTypeNumber0 != excelTypeNumber1)
            {
                return excelTypeNumber0.CompareTo(excelTypeNumber1);
            }

            switch (excelTypeNumber0)
            {
                case ExcelTypeNumber.Xdouble:
                    return ((double)value0).CompareTo((double)value1);
                case ExcelTypeNumber.Xstring:
                    return string.Compare((string)value0, (string)value1, true);
                case ExcelTypeNumber.Xbool:
                    return ((bool)value0).CompareTo((bool)value1);
                case ExcelTypeNumber.Xnull:
                    Debug.Assert(value1 == null); // real assert
                    return 0;
                default:
                    Debug.Assert(false); // real assert
                    return 0;
            }
        }


        private ExcelTypeNumber GetExcelTypeNumber(object value)
        {
            if (null == value)
            {
                return ExcelTypeNumber.Xnull;
            };


            switch (value.GetType().Name)
            {
                case "Int32":
                case "Double":
                    return ExcelTypeNumber.Xdouble;
                case "String":
                    return ExcelTypeNumber.Xstring;
                case "Boolean":
                    return ExcelTypeNumber.Xbool;
                default:
                    Debug.Assert(false, "don't type type " + value.GetType().Name);
                    return ExcelTypeNumber.Xnull;
            }
                
        }


        #endregion



        public List<Array> ArrayList;
        IEnumerable<string> CheckedItemCollection;
        internal static IEnumerable<Group> GetCollection(Excel.ListRows listRows, SortedDictionary<string, int> headerTable, IEnumerable<string> checkedItemCollection)
        {
            Group group = null;
            foreach (Excel.ListRow listRow in listRows)
            {
                Array array = (Array)listRow.Range.Value2;
                if (group != null)
                {
                    int iCompare = group.CompareTo(array);
                    if (iCompare == 0)
                    {
                        group.ArrayList.Add(array);
                    }
                    else
                    {
                        Debug.Assert(iCompare == -1); // real assert
                        yield return group;
                        group = null;
                    }
                }
                if (group == null) //Note that this can somtimes true even if "(group != null)" was true, too.
                {
                        group = new Group();
                        group.HeaderTable = headerTable;
                        group.CheckedItemCollection = checkedItemCollection;
                        group.ArrayList = new List<Array>();
                        group.ArrayList.Add(array);
                }
            }
            if (group != null)
            {
                yield return group;
            }
        }
    }

    public enum ExcelTypeNumber
    {
        Xdouble,
        Xstring,
        Xbool,
        Xnull
    }

}
// Microsoft Research, eScience Research Group, Microsoft Public License (Ms-PL)
// Copyright (c) Microsoft Corporation. All rights reserved. 